package br.cin.ufpe.feedbacktest.core;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.Vector;

public class FileGenerator {

	private static File packageFolder;
	private static String packageName;
	private static int successCount;
	private static int errorCount;
	private static ArrayList<String> successFiles;
	private static ArrayList<String> errorFiles;

	public static void initGenerator(File outputFolder, String packageName) {
		packageFolder = createPackageFolder(outputFolder, packageName);
		FileGenerator.packageName = packageName;
		successCount = 1;
		errorCount = 1;
		successFiles = new ArrayList<String>();
		errorFiles = new ArrayList<String>();
	}	

	public static void createSuccessSequence(Vector<Sequence> successSequence) throws IOException {
		String successFile = createTestCaseFile(true, successSequence, packageFolder, packageName);
		successFiles.add(successFile);
	}

	public static void createErrorSequence(Vector<Sequence> errorSequence) throws IOException {
		String successFile = createTestCaseFile(false, errorSequence, packageFolder, packageName);
		errorFiles.add(successFile);
	}

	public static void createTestSuites() throws IOException {
		createTestSuiteFiles(true, packageFolder ,packageName, successFiles);
		createTestSuiteFiles(false, packageFolder ,packageName, errorFiles);
	}

	private static File createPackageFolder(File outputFolder, String packageName) {
		if (packageName.trim().equals("")) {
			File[] oldFiles = outputFolder.listFiles();
			for (int i = 0; i < oldFiles.length; i++) {
				oldFiles[i].delete();
			}
			return outputFolder;
		}		

		if (!packageName.contains(".")) {
			File folder = new File(outputFolder, packageName);
			if (!folder.exists()) {
				folder.mkdir();
			} else {
				File[] oldFiles = folder.listFiles();
				for (int i = 0; i < oldFiles.length; i++) {
					oldFiles[i].delete();
				}
			}
			return folder;
		}

		StringTokenizer tokenizer = new StringTokenizer(packageName, ".");
		File folder = outputFolder;

		while (tokenizer.hasMoreTokens()) {
			String packagePart = tokenizer.nextToken();
			folder = new File(folder, packagePart);

			if (!folder.exists()) {
				folder.mkdir();
			} else {
				File[] oldFiles = folder.listFiles();
				for (int i = 0; i < oldFiles.length; i++) {
					oldFiles[i].delete();
				}
			}
		}

		return folder;
	}

	private static void createTestSuiteFiles(boolean successOrError, File dirName, String packageName, ArrayList<String> files) throws IOException {
		String className;		
		if (successOrError) {
			className = "ReggressionTestSuite";
		} else {
			className = "ErrorTestSuite";
		}

		StringBuffer buffer = new StringBuffer();		
		buffer.append("package " + packageName + ";");
		buffer.append("\n\n");
		buffer.append("import junit.framework.Test;\n");
		buffer.append("import junit.framework.TestSuite;\n");
		buffer.append("import junit.framework.TestCase;\n");
		buffer.append("import junit.framework.TestResult;\n");
		buffer.append("import junit.textui.TestRunner;\n");
		buffer.append("\n\n");
		buffer.append("public class ");
		buffer.append(className);
		buffer.append(" extends TestCase {\n\n");
		buffer.append("    public static void main(String[] args) {\n");
		buffer.append("      TestRunner runner = new TestRunner();\n");
		buffer.append("      TestResult result = runner.doRun(suite(), false);\n");
		buffer.append("      if (! result.wasSuccessful()) {\n");
		buffer.append("        System.exit(1);\n");
		buffer.append("      }\n");
		buffer.append("    }\n\n");
		buffer.append("    public static Test suite() {");
		buffer.append("\n");
		buffer.append("      TestSuite suite = new TestSuite();");
		buffer.append("\n");

		for (String fileName : files) {
			buffer.append("      suite.addTestSuite(");
			buffer.append(fileName);
			buffer.append(".class);\n");
		}
		buffer.append("      return suite;\n");

		buffer.append("	}\n");
		buffer.append("}");



		byte[] bytesString = buffer.toString().getBytes();

		File file = new File(dirName + File.separator + className + ".java");
		FileOutputStream out = new FileOutputStream(file);
		out.write(bytesString);
		out.flush();
		out.close();		
	}

	private static String createTestCaseFile(boolean successOrError, Vector<Sequence> sequences, File sourceFolder, String packageName) throws FileNotFoundException, IOException {
		StringBuffer buffer = new StringBuffer();
		int methodNumberCount = 1;

		String className;
		if (successOrError) {
			className = "RegressionTest" + successCount++;
		} else {
			className = "ErrorTest" + errorCount++;
		}

		buffer.append("package " + packageName + ";");
		buffer.append("\n\n");
		buffer.append("import junit.framework.TestCase;\n");		

		Vector<String> itImports = getImports(sequences);
		for(String tmpImport:itImports){
			buffer.append("import " + tmpImport + ";\n");
		}

		buffer.append("\n");
		buffer.append("public class ");			
		buffer.append(className);
		buffer.append(" extends TestCase {\n\n");
		
		buffer.append("    public static void main(String[] args) {\n");
		buffer.append("    		junit.textui.TestRunner.run(");
		buffer.append(className);
		buffer.append(".class);\n");
		buffer.append("    }\n\n");
		
		for(Sequence sequence:sequences){
			
			buffer.append("    public void testMethod"+methodNumberCount+"() throws Exception {\n");
			buffer.append(sequence.toString());

			if (successOrError) {
				buffer.append("\n");
				buffer.append(sequence.getAssertCall());
				buffer.append("\n");
			}
			methodNumberCount++;
			buffer.append("	}\n");
			
		}
		buffer.append("}");

		byte[] sourceBytes = buffer.toString().getBytes();

		File sourceFile = new File(sourceFolder + File.separator + className + ".java");
		FileOutputStream out = new FileOutputStream(sourceFile);
		out.write(sourceBytes);
		out.flush();
		out.close();			

		return className;
	}

	private static Vector<String> getImports(Vector<Sequence> sequences) {
		Vector<String> imports = new Vector<String>();

		for(Sequence sequence:sequences){
			for(String tempImport:sequence.getImports()){
				if(!imports.contains(tempImport)){
					imports.add(tempImport);
				}
			}			
		}

		return imports;
	}


}
